/**
 * pageca.c
 * 连续内存片段管理实现
 * 
 * 竹影半墙
 * 2023.08
 */
#include "pageca.h"

static unsigned pagesize;
static __always_inline unsigned pca_pagesize(void)
{
    if (unlikely(!pagesize))
        pagesize = getpagesize();
    return pagesize;
}

static __always_inline void * pca_end(struct pageca *pa)
{
    return (char*)pa->start + pa->size;
}

#define pa_real_size(ma) ({ma_max(ma->size, sizeof(void*));})

void pca_init(struct pageca *pa)
{
    void *s, *e;
    uint64_t pgnr;
    uint16_t size;
    struct memca *ma;

    ma = pa_to_ma(pa);
    size = pa_real_size(ma);
    pgnr = size * ma->max / pca_pagesize();
    ma->max -= pgnr * pca_pagesize() / size;
    pa->size = pgnr * pca_pagesize();

    mca_init(ma);
    if (!pgnr)
        return ;
    s = malloc(pgnr * pca_pagesize());
    pa->page = pa->start = s;
    e = (char*)s + pgnr*pca_pagesize();
    if (!s)
        return ;
    for (/* none */; s < e; s += size) {
        if (s + (size<<1) > e)
            break;
        *(void**)s = s + size;
    }
    *(void**)s = NULL;
    return ;
}

void pca_close(struct pageca *pa)
{
    mca_close(pa_to_ma(pa));
    free(pa->start);
    pa->page = pa->start = NULL;
    return ;
}

void * pca_alloc(struct pageca *pa)
{
    void *v;
    struct memca *ma = pa_to_ma(pa);

    v = ma_alloc(ma, &pa->page, 0);
    return v ?: mca_alloc(ma);
}

void pca_free(struct pageca *pa, void *v)
{
    struct memca *ma;
    void *end = pca_end(pa);

    ma = pa_to_ma(pa);
    if (pa->start <= v && v < end) {
        ma_free(ma, &pa->page, v, 1);
        return ;
    }
    mca_free(ma, v);
    return ;
}

void * pca_swap(struct pageca *pa, void *v)
{
    void *vp;
    struct memca *ma;
    void *end = pca_end(pa);

    if (pa->start <= v && v < end)
        return v;
    ma = pa_to_ma(pa);
    vp = ma_alloc(ma, &pa->page, 0);
    if (!vp)
        return v;
    memcpy(vp, v, ma->size);
    ma_free(ma, &ma->head, v, 1);
    return vp;
}